package com.rhino.security.datasourceaccess;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName MyFilterInvocationSecurityMetadataSource
 * @Description 这个自定义类是用来匹配当前用户访问资源的URL和数据库中对该资源URL的访问需要哪些权限-角色。
 * 访问这URL需要哪些角色。
 * @Author zyk
 * @Create 2021/7/12
 * @Version 1.0
 **/
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    /**
     * 用于实现ant风格的Url匹配
     */
    AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 返回所有菜单及对应的角色
     * 说明：访问某个菜单需要哪些角色 1个菜单对应N个角色；
     * 正常业务，给菜单配置角色--权限，都保存到数据库中，这里模拟从数据库读取数据。
     * 也可出入参数，当前登录用户的角色获取菜单;一般会把所有菜单数据保存到缓存中，减少数据库访问；
     * @return
     */
    private Map<String, List<String>> getAllMenu(){
        Map<String,List<String>> menus=new HashMap<>();

        List<String> menu=new ArrayList<>();
        menu.add("ROLE_Employee");
        menu.add("ROLE_Manager");
        menus.put("/test/**",menu);

        List<String> admin=new ArrayList<>();
        admin.add("ROLE_Admin");
        menus.put("/admin/**",admin);
        return menus;
    }

    /**
     * 获取访问当前URL都需要哪些角色，从菜单授权中获取角色信息
     * @param o
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        //获取当前用户请求的URL
        String requestUrl = ((FilterInvocation) o).getRequestUrl();

        //当前访问的URL需要哪些角色可访问
        Map<String, List<String>> allMenu = getAllMenu();
        for (String menu:allMenu.keySet()){
            if(antPathMatcher.match(menu,requestUrl)){
                List<String> accessRoles = allMenu.get(menu);
                String[] roles=new String[accessRoles.size()];
                for(int i=0;i<roles.length;i++){
                    roles[i]=accessRoles.get(i);
                }
                return SecurityConfig.createList(roles);
            }
        }

        //当前菜单没有配置角色
        //没有配置权限时，默认"ROLE_LOGIN"，不需要权限控制。可直接访问
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}
